JaxbXmlSqlReader의 개선 사항

  1. XML과 자바오브젝트를 매핑하는 JAXB 외의 기술을 손쉽게 바꿔 사용할 수 있도록 한다.

  2. XML 파일을 좀 더 다양한 소스에서 가져올 수 있게 한다.

OXM 서비스 추상화

XML과 자바오브젝트를 매핑해서 상호 변환해주는 기술을 OXM(Object-XML-Mapping)이라고 하는데, OXM 프레임워크와 기술들은 기능 면에서 상호 호환성이 있다. 그러므로 이를 사용하는 코드에는 특정 API에 종속되지 않게 해주는 서비스 추상화가 필요하다. 스프링은 트랜잭션, 메일 전송뿐 아니라 OXM에 대해서도 서비스 추상화 기능을 제공한다.

OXM 서비스 인터페이스

스프링이 제공하는 OXM 추상화 서비스 인터페이스에는 XML을 자바 오브젝트로 변환하는 Unmarshaller가 있다. XML 파일에 대한 정보를 담은 Source 타입의 오브젝트를 주면, 설정에서 지정한 OXM 기술을 이용해 자바오브젝트 트리로 변환하고, 루트 오브젝트를 돌려준다.

JAXB 구현 테스트

JAXB를 이용하도록 만들어진 Unmarshaller구현 클래스는 Jaxb2Marshaller이다. Jaxb2Marshaller를 클래스 빈으로 등록하고 바인딩 클래스의 패키지 이름을 지정하는 프로퍼티인 contextPath만 넣어주자.

추상 인터페이스인 Unmarshallerunmarshal() 메소드를 한 번 호출해주기만 하면 모든 번거로운 작업은 Jaxb2Marshaller빈이 알아서 진행해줄 것이다.

Castor 구현 테스트

Caster는 여러가지 XML/오브젝트 변환 방법을 지원하는데, 그중에서 간단하게 정의해서 사용할 수 있는 XML 매핑파일을 이용해보자. 매핑정보만 적절히 만들어 주면 어떤 클래스와 필드로도 매핑이 가능하기 때문에 JAXB 컴파일러가 만들어줬던 Sqlmap, SqlType 클래스를 Caster매핑용으로 사용해도 된다.

OXM 서비스 추상화 적용

이제 스프링의 OXM 추상화 기능을 이용하는 SqlService를 만들어보자. SQL을 읽는 방법을 OXM으로 제한해서 사용성을 극대화하는 게 목적이다.

멤버 클래스를 참조하는 통합 클래스

BaseSqlService와 유사하게 SqlReader 타입의 의존 오브젝트를 사용하되 이를 스태틱 멤버 클래스로 내장하고 자신만이 사용할 수 있는 OxmSqlService를 만들어보자.
의존 오브젝트를 자신만이 사용하도록 독점하는 구조로 만드는 방법이다

스프링의 OXM 서비스 추상화를 사용하면 언마샬러를 빈으로 등록해야 한다. SqlService를 위해 등록할 빈은 자꾸 늘어난다.
이러한 경우에는 하나의 빈 설정만으로 SqlServiceSqlReader의 필요한 프로퍼티 설정이 모두 가능하도록 만들 필요가 있다.

OxmSqlService로 등록한 빈의 프로퍼티 일부는 OxmSqlService 내부의 OxmSqlReader프로퍼티를 설정해주기 위한 창구 역할을 하게 한다.

위임을 이용한 BaseSqlService의 재사용

BaseSqlSeviceOxmSqlService의 중복된 코드를 제거해보자. loadSql()getSql()의 구현 로직은 BaseSqlService에만 두고, OxmSqlService는 일종의 설정과 기본 구성을 변경해주기 위한 어댑터 같은 개념으로 BaseSqlSerive의 앞에 두는 설계가 가능하다. OxmSqlService의 외형적은 틀은 유지한 채로 SqlService의 기능 구현은 BaseSqlService로 위임하는 것이다.

리소스 추상화

공통된 문제점이 하나 해결안되었다. 바로 SQL 매핑 정보가 담긴 XML 파일 이름을 프로퍼티로 외부에서 지정할 수는 있지만, UserDao클래스와 같은 클래스패스에 존재하는 파일로 제한된다는 점이다.

리소스에 접근할 수 있는 통일된 방법이 있다면 좋을것 같다.

리소스

스프링은 자바에 존재하는 일관성 없는 리소스 접근 API를 축상화해서 Resource라는 추상화 인터페이스를 정의했다.

다른 서비스 추상화 오브젝트와는 달리, Resource는 스프링에서 빈이 아니라 값으로 취급된다. 단순한 정보를 가진 값으로 지정되기 때문에, 클래스로 지정할 수가 없다.

리소스 로더

그래서 스프링에는 URL클래스와 유사하게 접두어를 이용해 Resource 오브젝트를 선언하는 방법이 있다. 문자열 안에 리소스 종류와 리소스의 위치를 함께 표현하게 해주는 것이다.
그리고 이렇게 문자열로 정의된 리소스를 실제 Resource타입 오브젝트로 변환해주는 ResourceLoader를 제공한다.

대표적인 ResourceLoader은 애플리케이션 컨텍스트다. 에플리케이션 컨텍스트가 구현해야 하는 인터페이스인 ApplicationContextResourceLoader 인터페이스를 상속하고 있다. 따라서 모든 애플리케이션 컨텍스트는 리소스 로더이기도 하다.

Resource를 이용해 XML 파일 가져오기

OxmSqlServiceResource를 적용해서 SQL 매핑정보가 담긴 파일을 다양한 위치에서 가져올 수 있게 만들어보자.

스트링으로 되어 있던 sqlmapFile프로퍼티를 모두 Resource 타입으로 바꾼다.
Resource타입은 실제 소스가 어떤 것이든 상관없이 getInputStream() 메소드를 이용해 스트림으로 가져올 수 있다.